﻿#region

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Principal;
using System.Threading;
using System.Web;
using System.Web.Http;
using System.Web.Security;
using Mvc.Mailer;
using log4net;
using xConnected.Core.Interfaces.Data;
using xConnected.Core.Interfaces.Service;
using xConnected.Core.Model;
using xConnected.Core.Model.ViewModel;
using xConnected.Mailers;

#endregion

namespace xConnected.Web.Controllers
{
    public class AccountController : ApiController
    {
        private const string accountNotActivatedError = "Your account is not activated. Please activate your account.";
        private const string passwordNotMatch = "Password doesn't match.";
        private const string userNotExists = "User doesn't exist.";
        private const string emailExists = "This email already exists. Please enter new email.";
        private const string typeAgain = "Please type again, the two words bellow.";

        protected ICompanyProfileService CompanyService;
        protected IExpertProfileService ProfileService;
        protected IUnitOfWork UnitOfWork;
        protected IUserService _userService;

        public AccountController(IUserService userService, IExpertProfileService profileService,
                                 ICompanyProfileService companyService, IUnitOfWork unitOfWork)
        {
            _userService = userService;
            ProfileService = profileService;
            CompanyService = companyService;
            UnitOfWork = unitOfWork;
        }

        public HttpResponseMessage Activate(RegisterModel registerModel)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var user = _userService.GetAll().First(u => u.ActivationKey == registerModel.ActivationKey);
                user.IsActivated = true;
                _userService.SaveOrUpdate(user);
                return new HttpResponseMessage(HttpStatusCode.OK);
            }

            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                throw new HttpResponseException(HttpStatusCode.NotImplemented);
            }
        }

        public HttpResponseMessage SendWelcomeMessage(RegisterModel registerModel)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var mailer = new UserMailer();
                var user = _userService.GetUserByEmail(registerModel.Email);
                var msg = mailer.Welcome(user.Email, user.Username, user.ActivationKey);
                msg.Send();
                return new HttpResponseMessage(HttpStatusCode.OK);
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                return new HttpResponseMessage(HttpStatusCode.NotImplemented);
            }
        }

        public HttpResponseMessage SignIn(LogOnModel logOn)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                //if this is automatic sign in find user by ativationkey
                var user = logOn.WasJustActivated
                               ? _userService.GetAll().First(u => u.ActivationKey == logOn.ActivationKey)
                               : _userService.GetUserByUsername(logOn.Username);


                if (user != null)
                {
                    if (user.Password == logOn.Password || logOn.WasJustActivated)
                    {
                        if (user.IsActivated)
                        {
                            LogOn(user, logOn.RememberMe);

                            return new HttpResponseMessage(HttpStatusCode.OK);
                        }

                        var responseAccountNotActivated = Request.CreateResponse(HttpStatusCode.ExpectationFailed,
                                                                                 accountNotActivatedError);
                        return responseAccountNotActivated;
                    }
                    var responsePasswordNotMatch = Request.CreateResponse(HttpStatusCode.ExpectationFailed,
                                                                          passwordNotMatch);
                    return responsePasswordNotMatch;
                }
                var responseUserNotExists = Request.CreateResponse(HttpStatusCode.ExpectationFailed, userNotExists);
                return responseUserNotExists;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                return new HttpResponseMessage(HttpStatusCode.ExpectationFailed);
            }
        }

        protected internal void LogOn(User user, bool rememberMe)
        {
            var principal = new GenericPrincipal(new GenericIdentity(user.Username), new string[] {});

            if (HttpContext.Current != null)
            {
                DateTime expires = DateTime.Now.AddDays(20);
                var ticket = new FormsAuthenticationTicket(
                    1, // Version
                    user.Username, // Username
                    DateTime.Now, // Creation
                    expires, // Expiration
                    rememberMe, // Persistent
                    user.SerializeForTicket()
                    );

                string encryptedTicket = FormsAuthentication.Encrypt(ticket);
                var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
                if (ticket.IsPersistent)
                    authCookie.Expires = expires;
                HttpContext.Current.Response.Cookies.Add(authCookie);
            }
            else
            {
                Thread.CurrentPrincipal = principal;
            }
        }

        public HttpResponseMessage SignOut()
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                if (HttpContext.Current != null)
                {
                    FormsAuthentication.SignOut();
                    HttpContext.Current.User = null;
                }
                else
                {
                    Thread.CurrentPrincipal = null;
                }

                return new HttpResponseMessage(HttpStatusCode.OK);
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                return new HttpResponseMessage(HttpStatusCode.ExpectationFailed);
            }
        }


        public HttpResponseMessage Register(RegisterModel registerModel)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var captchaValid = true;
                if (captchaValid)
                {
                    var emailUsed = _userService.GetUserByEmail(registerModel.Email) != null;
                    if (emailUsed)
                    {
                        var responseEmailExists = Request.CreateResponse(HttpStatusCode.ExpectationFailed, emailExists);
                        return responseEmailExists;
                    }

                    var user = new User
                                   {
                                       Email = registerModel.Email,
                                       Password = registerModel.Password,
                                       Username = registerModel.Username,
                                       ActivationKey = Guid.NewGuid(),
                                       //create block lists for the new user
                                       ExpertLists = new List<ExpertList> { new ExpertList { Name = "BlockList", IsBlackList = true } },
                                       CompanyLists = new List<CompanyList> { new CompanyList { Name = "BlockList", IsBlackList = true } },
                                       PositionLists = new List<PositionList> { new PositionList { Name = "BlockList", IsBlackList = true } },
                                   };
                    _userService.SaveOrUpdate(user);
                    UnitOfWork.Commit();

                    //create the directory structure
                    var di1 =
                        new DirectoryInfo(HttpContext.Current.Server.MapPath("~/Content/Uploads/" + user.Username));
                    di1.Create();

                    var di2 =
                        new DirectoryInfo(
                            HttpContext.Current.Server.MapPath("~/Content/Uploads/" +
                                                               Path.Combine(user.Username, "ExpertProfiles")));
                    di2.Create();

                    var di3 =
                        new DirectoryInfo(
                            HttpContext.Current.Server.MapPath("~/Content/Uploads/" +
                                                               Path.Combine(user.Username, "CompanyProfiles")));
                    di3.Create();

                    return new HttpResponseMessage(HttpStatusCode.OK);
                }

                var responseTypeAgain = Request.CreateResponse(HttpStatusCode.ExpectationFailed, typeAgain);
                return responseTypeAgain;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
            }
        }
    }
}